home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mgr / rmgr.arc / rmgr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-03-08  |  31.7 KB  |  1,469 lines

  1. /* Copyright (c) 1987,1988 Oliver Laumann, Technical University of Berlin.
  2.  * Not derived from licensed software.
  3.  *
  4.  * Permission is granted to freely use, copy, modify, and redistribute
  5.  * this software, provided that no attempt is made to gain profit from it,
  6.  * the author is not construed to be liable for any results of using the
  7.  * software, alterations are clearly marked as such, and this notice is
  8.  * not modified.
  9.  */
  10.  
  11. /* This program Copyright 1990 by Howard Chu.
  12.  *
  13.  * This is rmgr, a remote window manager for Bellcore's MGR window
  14.  * manager, by Howard Chu @ University of Michigan (Ann Arbor, MI).
  15.  * Much of this program consists of Oliver Laumann's code; I have not
  16.  * (usually) highlighted my changes in any way. Oliver didn't use any
  17.  * comments at all; for the most part I have followed his lead...  }-)
  18.  * Suffice to say, some of the routines are original, some are heavily
  19.  * hacked upon versions of his code, and some are untouched from his
  20.  * program. Of course, the volume of code here represents only half
  21.  * of the code used in the screen program; the rest, support for ANSI
  22.  * terminal emulation, was discarded.
  23.  */
  24.  
  25. static char Version[] = "$Header: /usr/src/rmgr/RCS/rmgr.c,v 1.5 90/10/15 03:39:02 hyc Stable $";
  26.  
  27. #include <stdio.h>
  28. #include <sgtty.h>
  29. #include <signal.h>
  30. #include <errno.h>
  31. #include <ctype.h>
  32. #include <utmp.h>
  33. #include <pwd.h>
  34. #include <nlist.h>
  35. #include <fcntl.h>
  36. #include <sys/types.h>
  37. #include <sys/time.h>
  38. #include <sys/file.h>
  39. #include <sys/wait.h>
  40. #include <sys/socket.h>
  41. #include <sys/un.h>
  42. #include <sys/stat.h>
  43. #include <sys/dir.h>
  44. #include "rmgr.h"
  45.  
  46. #ifdef GETTTYENT
  47. #   include <ttyent.h>
  48. #else
  49.     static struct ttyent {
  50.     char *ty_name;
  51.     } *getttyent();
  52.     static char *tt, *ttnext;
  53.     static char ttys[] = "/etc/ttys";
  54. #endif
  55.  
  56. #define MAXWIN     10
  57. #define MSGWAIT     5
  58.  
  59. #define Ctrl(c) ((c)&037)
  60.  
  61. extern char **environ;
  62. extern errno;
  63. extern sys_nerr;
  64. extern char *sys_errlist[];
  65. extern char *index(), *rindex(), *malloc(), *getenv(), *MakeTermcap();
  66. extern char *getlogin(), *ttyname();
  67. static void AttacherFinit(), Finit(), SigHup(), SigChld();
  68. static char *Filename(), **SaveArgs(), *GetTtyName();
  69.  
  70. static char PtyName[32], TtyName[32];
  71. static char *ShellProg;
  72. static char *ShellArgs[2];
  73. static char inbuf[IOSIZE];
  74. static inlen;
  75. static ESCseen;
  76. static GotSignal;
  77. static char DefaultShell[] = "/bin/sh";
  78. static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
  79. static char PtyProto[] = "/dev/ptyXY";
  80. static char TtyProto[] = "/dev/ttyXY";
  81. static int TtyMode = 0622;
  82. static char SockPath[512];
  83. static char SockDir[] = ".rmgr";
  84. static char *SockNamePtr, *SockName;
  85. static ServerSocket;
  86. static char *NewEnv[MAXARGS];
  87. static char Esc = Ctrl('a');
  88. static char *home;
  89. static HasWindow;
  90. static utmp, utmpf;
  91. static char UtmpName[] = "/etc/utmp";
  92. static char *LoginName;
  93. static char HostName[MAXSTR];
  94. static Detached;
  95. static AttacherPid;    /* Non-Zero in child if we have an attacher */
  96. static DevTty;
  97. static char EventStr[]="%c%cA";
  98. static char CommNames[MAXLINE];
  99. static int VoluntaryDetach = 0;
  100. static int MyFont;
  101.  
  102. struct mode {
  103.     struct sgttyb m_ttyb;
  104.     struct tchars m_tchars;
  105.     struct ltchars m_ltchars;
  106.     int m_ldisc;
  107.     int m_lmode;
  108. } OldMode, NewMode;
  109.  
  110. static struct win *curr, *other;
  111. static CurrNum, OtherNum;
  112. static struct win *wtab[MAXWIN];
  113.  
  114. main (ac, av) char **av; {
  115.     register n, len;
  116.     register struct win **pp, *p;
  117.     char *ap;
  118.     static InitMenu();
  119.     int s, r, w, x = 0;
  120.     int rflag = 0;
  121.     struct timeval tv;
  122.     time_t now;
  123.     char buf[IOSIZE], *myname = (ac == 0) ? "rmgr" : av[0];
  124.     struct stat st;
  125.     char *winname="";
  126.  
  127.     while (ac > 0) {
  128.     ap = *++av;
  129.     if (--ac > 0 && *ap == '-') {
  130.         switch (ap[1]) {
  131.         case 'r':
  132.         rflag = 1;
  133.         if (ap[2]) {
  134.             SockName = ap+2;
  135.             if (ac != 1) goto help;
  136.         } else if (--ac == 1) {
  137.             SockName = *++av;
  138.         } else if (ac != 0) goto help;
  139.         break;
  140.         case 'n':
  141.         if (ap[2]) {
  142.             ap += 2;
  143.         } else {
  144.             if (--ac == 0) goto help;
  145.             ap = *++av;
  146.         }
  147.         winname=ap;
  148.         break;
  149.         default:
  150.         help:
  151.         Msg (0, "Use: %s [-n windowname] [cmd args]\n\
  152.  or: %s -r [host.tty]", myname, myname);
  153.         }
  154.     } else break;
  155.     }
  156.     CommNames[0]='}';
  157.     if ((ShellProg = getenv ("SHELL")) == 0)
  158.     ShellProg = DefaultShell;
  159.     ShellArgs[0] = ShellProg;
  160.     if (ac == 0) {
  161.     ac = 1;
  162.     av = ShellArgs;
  163.     }
  164.     if ((home = getenv ("HOME")) == 0)
  165.     Msg (0, "$HOME is undefined.");
  166.     sprintf (SockPath, "%s/%s", home, SockDir);
  167.     if (stat (SockPath, &st) == -1) {
  168.     if (errno == ENOENT) {
  169.         if (mkdir (SockPath, 0700) == -1)
  170.         Msg (errno, "Cannot make directory %s", SockPath);
  171.         (void) chown (SockPath, getuid (), getgid ());
  172.     } else Msg (errno, "Cannot get status of %s", SockPath);
  173.     } else {
  174.     if ((st.st_mode & S_IFMT) != S_IFDIR)
  175.         Msg (0, "%s is not a directory.", SockPath);
  176.     if ((st.st_mode & 0777) != 0700)
  177.         Msg (0, "Directory %s must have mode 700.", SockPath);
  178.     if (st.st_uid != getuid ())
  179.         Msg (0, "You are not the owner of %s.", SockPath);
  180.     }
  181.     (void) gethostname (HostName, MAXSTR);
  182.     HostName[MAXSTR-1] = '\0';
  183.     if (ap = index (HostName, '.'))
  184.     *ap = '\0';
  185.     strcat (SockPath, "/");
  186.     SockNamePtr = SockPath + strlen (SockPath);
  187.     if ((DevTty = open ("/dev/tty", O_RDWR|O_NDELAY)) == -1)
  188.     Msg (errno, "/dev/tty");
  189.     if (rflag) {
  190.     Attach (MSG_ATTACH);
  191.     Attacher ();
  192.     /*NOTREACHED*/
  193.     }
  194.     if (GetSockName ()) {
  195.     s = MakeClientSocket (1);
  196.     SendCreateMsg (s, ac, av, winname);
  197.     close (s);
  198.     exit (0);
  199.     }
  200.     switch (fork ()) {
  201.     case -1:
  202.     Msg (errno, "fork");
  203.     /*NOTREACHED*/
  204.     case 0:
  205.     break;
  206.     default:
  207.     Attacher ();
  208.     /*NOTREACHED*/
  209.     }
  210.     AttacherPid = getppid ();
  211.     ServerSocket = s = MakeServerSocket ();
  212.     InitTerm ();
  213.     InitMenu ();
  214.     MakeNewEnv ();
  215.     GetTTY (0, &OldMode);
  216.     InitUtmp ();
  217.     signal (SIGHUP, SigHup);
  218.     signal (SIGINT, Finit);
  219.     signal (SIGQUIT, Finit);
  220.     signal (SIGTERM, Finit);
  221.     signal (SIGTTIN, SIG_IGN);
  222.     signal (SIGTTOU, SIG_IGN);
  223.     if ((n = MakeWindow (*av, av, winname, (char *)0)) == -1) {
  224.     SetTTY (0, &OldMode);
  225.     FinitTerm ();
  226.     Kill (AttacherPid, SIGHUP);
  227.     exit (1);
  228.     }
  229.     SetCurrWindow (n);
  230.     HasWindow = 1;
  231.     SetMode (&OldMode, &NewMode);
  232.     SetTTY (0, &NewMode);
  233.     signal (SIGCHLD, SigChld);
  234.     tv.tv_usec = 0;
  235.     while (1) {
  236.     r = 0;
  237.     w = 0;
  238.     if (inlen && curr->wpid>=0)
  239.         w |= 1 << curr->ptyfd;
  240.     else
  241.         r |= 1 << 0;
  242.     for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
  243.         if (!(p = *pp))
  244.         continue;
  245.         if (p->wpid >=0)
  246.             r |= 1 << p->ptyfd;
  247.     }
  248.     r |= 1 << s;
  249.     (void) fflush (stdout);
  250.     if (GotSignal) {
  251.         SigHandler ();
  252.         continue;
  253.     }
  254.     if (select (32, &r, &w, &x, (struct timeval *)0) == -1) {
  255.         if (errno == EINTR)
  256.         continue;
  257.         HasWindow = 0;
  258.         Msg (errno, "select");
  259.         /*NOTREACHED*/
  260.     }
  261.     if (GotSignal) {
  262.         SigHandler ();
  263.         continue;
  264.     }
  265.     if (r & 1 << s) {
  266.         ReceiveMsg (s);
  267.     }
  268.     if (r & 1 << 0) {
  269.         if (ESCseen) {
  270.         inbuf[0] = Esc;
  271.         inlen = read (0, inbuf+1, IOSIZE-1) + 1;
  272.         ESCseen = 0;
  273.         } else {
  274.         inlen = read (0, inbuf, IOSIZE);
  275.         }
  276.         if (inlen > 0)
  277.         inlen = ProcessInput (inbuf, inlen);
  278.         if (inlen > 0)
  279.         continue;
  280.     }
  281.     if (GotSignal) {
  282.         SigHandler ();
  283.         continue;
  284.     }
  285.     if (curr && w & 1 << curr->ptyfd && inlen > 0) {
  286.         if ((len = write (curr->ptyfd, inbuf, inlen)) > 0) {
  287.         inlen -= len;
  288.         bcopy (inbuf+len, inbuf, inlen);
  289.         }
  290.     }
  291.     if (GotSignal) {
  292.         SigHandler ();
  293.         continue;
  294.     }
  295.     for (n=0; n<MAXWIN; n++) {
  296.         if (!(p = wtab[n]))
  297.         continue;
  298.         if (r & 1 << p->ptyfd) {
  299.         if ((len = read (p->ptyfd, buf, IOSIZE)) == -1) {
  300.             if (errno == EWOULDBLOCK)
  301.             len = 0;
  302.         }
  303.         if (len > 0)
  304.             WriteString (n, buf, len);
  305.         }
  306.     }
  307.     if (GotSignal)
  308.         SigHandler ();
  309.     }
  310.     /*NOTREACHED*/
  311. }
  312.  
  313. static InitTerm() {
  314.     register char *s;
  315.  
  316.     if ((s = getenv("TERM")) == 0)
  317.     Msg(0, "No TERM in environment.");
  318.     if (strcmp(s,"mgr"))
  319.     Msg(0, "Only runs on mgr terminals.");
  320.  
  321.     m_setup(M_FLUSH);
  322.     m_push(P_DEFAULT|P_POSITION);
  323.     MyFont=get_font(NULL,NULL);
  324.     m_dupkey(Esc);
  325. }
  326.  
  327. static FinitTerm() {
  328.     m_nomenu2(); m_nomenu();
  329.     m_clearmenu(1); m_clearmenu(2);
  330.     m_clearevent(ACTIVATE); m_clearevent(RESHAPE); m_clearevent(DESTROY);
  331.     m_popall();
  332. }
  333.     
  334. static WriteString(n, buf, len) int n, len; char *buf; {
  335.     register int i, j;
  336.     register struct win *p;
  337.  
  338.     p=wtab[n];
  339.  
  340.     if (!Detached) {
  341.     m_selectwin(n);
  342.     write(fileno(m_termout), buf, len);
  343.     } else
  344.     p->win_ok=0;        /* Screen no longer matches reality... */
  345.  
  346.     i=SCRBUFSIZE - (p->outptr - p->outbuf);
  347.     if (i>=len) {
  348.     bcopy(buf,p->outptr,len);
  349.     if (i==len) {
  350.         p->outptr=p->outbuf;
  351.         p->outful=1;
  352.     } else
  353.         p->outptr+=len;
  354.     } else {
  355.     j=len-i;
  356.     bcopy(buf,p->outptr,i);
  357.     bcopy(&buf[i],p->outbuf,j);
  358.     p->outptr=p->outbuf+j;
  359.     p->outful=1;
  360.     }
  361. }
  362.  
  363. static SigHandler () {
  364.     while (GotSignal) {
  365.     GotSignal = 0;
  366.     DoWait ();
  367.     }
  368. }
  369.  
  370. static void SigChld () {
  371.     GotSignal = 1;
  372. }
  373.  
  374. static void SigHup () {
  375.     Detach (0);
  376. }
  377.  
  378. static DoWait () {
  379.     register pid;
  380.     register int n;
  381.     register struct win **pp;
  382.     union wait wstat;
  383.  
  384.     while ((pid = wait3 (&wstat, WNOHANG|WUNTRACED, NULL)) > 0) {
  385.     for (n = 0; n<MAXWIN; n++) {
  386.         if (wtab[n] && pid == wtab[n]->wpid) {
  387.         if (WIFSTOPPED (wstat)) {
  388.             (void) killpg (getpgrp (wtab[n]->wpid), SIGCONT);
  389.         } else
  390.             KillWindow(n);
  391.         }
  392.     }
  393.     }
  394.     for (n=0; n<MAXWIN; n++)
  395.     if (wtab[n] && wtab[n]->wpid >=0)
  396.         break;
  397.     if (n == MAXWIN)
  398.     Finit();
  399. }
  400.  
  401. static KillWindow (n) int n; {
  402.     if (Detached || n!=CurrNum || !n) {
  403.     WriteString(n,"[window shut down]",18);
  404.     wtab[n]->wpid = -1;    /* Shut it down, but don't close */
  405.     if (!n)
  406.             FreeWindow (n);    /* Don't ever close window 0, but free it */
  407.     } else {
  408.     CurrNum = 0;
  409.     curr = 0;
  410.         FreeWindow (n);
  411.     }
  412. }
  413.  
  414. static void Finit () {
  415.     register int n;
  416.     register struct win *p, **pp;
  417.  
  418.     for (n=0; n<MAXWIN; n++) {
  419.     if (wtab[n])
  420.         FreeWindow(n);
  421.     }
  422.     SetTTY (0, &OldMode);
  423.     FinitTerm ();
  424.     printf ("\r[rmgr is terminating]\033c\n");
  425.     Kill (AttacherPid, SIGHUP);
  426.     exit (0);
  427. }
  428.  
  429. static linemode(onoff) int onoff; {
  430.     struct sgttyb buff;
  431.     gtty(0,&buff);
  432.     if (onoff)
  433.         buff.sg_flags &= ~CBREAK;
  434.     else
  435.         buff.sg_flags |= CBREAK;
  436.     stty(0,&buff);
  437. }
  438.  
  439. static ProcessInput (buf, len) char *buf; {
  440.     register n, k;
  441.     register char *s, *p, *q;
  442.     register struct win **pp;
  443.  
  444.     for (s = p = buf; len > 0; len--, s++) {
  445.     if (*s == Esc) {
  446.         if (len > 1) {
  447.         len--; s++;
  448.         if (*s == Esc) {
  449.             *p++ = Esc;
  450.         } else {        /* Process event or menu string */
  451.         if (*s != ' ') {
  452.             n=(*s++)-'!';
  453.             len--;
  454.             if (!len) {        /* Make sure to get 3rd char */
  455.             while(!read(0,s,1));
  456.             len++;
  457.             }
  458.             p=buf;
  459.             switch (*s) {    /* Event Strings */
  460.             case 'A':
  461.                 SetCurrWindow(n);
  462.                 break;
  463.             case 'D':
  464.                 FreeWindow(n);
  465.                 break;
  466.             case 'R':
  467.                 SizeWindow(n);
  468.                 break;
  469.             case 'c':    /* Menu Strings */
  470.                 if ((n=MakeWindow((char *)0, (char *)0,
  471.                     "", (char *)0)) != -1)
  472.                     SetCurrWindow(n);
  473.                 break;
  474.             case 'd':
  475.                 VoluntaryDetach=1;
  476.                 Detach(0);
  477.                 break;
  478.             case 'f':
  479.                 SwitchWindow(n);
  480.                 break;
  481.             case 'k':
  482.                 KillWindow(n);
  483.                 break;
  484.             case 'n':
  485.                 if ((n=MakeWindow(ShellProg, ShellArgs,
  486.                     "", (char *)0)) != -1)
  487.                     SetCurrWindow(n);
  488.                 break;
  489.             case 'q':
  490.                 Finit();
  491.                 break;
  492.             case 's':
  493.                 VoluntaryDetach=1;
  494.                 Detach(1);
  495.                 break;
  496.             }
  497.             }
  498.         } 
  499.         } else ESCseen = 1;
  500.     } else *p++ = *s;
  501.     }
  502.     return p - buf;
  503. }
  504.  
  505. static SwitchWindow(n) {
  506.     if (wtab[n]) {
  507.         SetCurrWindow(n);
  508.         m_setmode(M_ACTIVATE);
  509.     }
  510. }
  511.  
  512. static SetCurrWindow (n) {
  513.     CurrNum = n;
  514.     curr = wtab[n];
  515.     m_selectwin(n);
  516.     if (curr->wpid < 0)
  517.     m_setmode(M_NOINPUT);    /* Dead window, disallow input */
  518. }
  519.  
  520. static SizeWindow (n) int n; {
  521.     struct winsize wbuf;
  522.     char buf[32]; 
  523.  
  524.     m_selectwin(n);
  525.     m_getinfo(G_WINSIZE);
  526.     linemode(1);
  527.     read(0,buf,31);
  528.     linemode(0);
  529.     buf[31]='\0';
  530.     sscanf(buf,"%*c %d %d",&(wtab[n]->cols),&(wtab[n]->rows));
  531. #ifdef    TIOCSWINSZ
  532.     wbuf.ws_row = wtab[n]->rows;
  533.     wbuf.ws_col = wtab[n]->cols;
  534.     ioctl (wtab[n]->ptyfd, TIOCSWINSZ, &wbuf);
  535. #endif
  536. }
  537.  
  538. static FreeWindow (n) register int n; {
  539.     register i;
  540.     register struct win *wp;
  541.  
  542.     wp=wtab[n];
  543.     if (wp) {
  544.         RemoveUtmp (wp->slot);
  545.         (void) chmod (wp->tty, 0666);
  546.         (void) chown (wp->tty, 0, 0);
  547.         close (wp->ptyfd);
  548.         free (wp);
  549.         wtab[n]=0;
  550.     }
  551.     if (n) {
  552.     m_selectwin(n);
  553.     m_clearevent(DESTROY);    /* Avoid redundant calling of FreeWindow */
  554.     m_destroywin(n);
  555.     }
  556.     CollectNames();
  557.     sleep(1);
  558.     UpdateMenu(n);
  559. }
  560.  
  561. static CollectNames() {        /* Collect command names for second menu */
  562.     register struct win **wp;
  563.     register int n;
  564.     char buf[8];
  565.  
  566.     CommNames[1]='\0';
  567.     for (wp=wtab; wp<wtab+MAXWIN; wp++)
  568.     if (*wp) {
  569.         strcat(CommNames,(*wp)->cmd);
  570.         strcat(CommNames,"}");
  571.     }
  572.  
  573.     buf[0]=Esc;
  574.     buf[1]='!';
  575.     buf[2]='f';
  576.     buf[3]='}';
  577.     buf[4]='\0';
  578.     for (n=0;n<MAXWIN;n++)
  579.     if (wtab[n]) {
  580.         buf[1]=n+'!';
  581.         strcat(CommNames,buf);
  582.     }
  583. }
  584.  
  585. static char *MenuNames[]={"MGR Windows =>", "", "-=-=-=-=-=-=-",
  586.     "Shell Window","Other Window","Kill Window","Suspend","Detach","Quit"};
  587. static char MenuNull='\0';
  588. static char MenuActs[24];
  589. static char MenuLabs[8]="ncksdq";
  590. static struct menu_entry MainMenu[9];
  591.  
  592. static InitMenu() {
  593.     register int i;
  594.     register char *ptr;
  595.  
  596.     ptr=MenuActs;
  597.     for (i=3;i<9;i++) {
  598.     MainMenu[i].action=ptr;
  599.     *ptr++=Esc;
  600.     *ptr++='!';
  601.     *ptr++=MenuLabs[i-3];
  602.     *ptr++='\0';
  603.     }
  604.     for (i=0;i<3;i++)
  605.     MainMenu[i].action=(&MenuNull);
  606.  
  607.     for (i=0;i<9;i++)
  608.     MainMenu[i].value=MenuNames[i];
  609. }
  610.  
  611. static MakeMenu(n) int n; {
  612.     MenuActs[9]=n+'!';
  613.     MainMenu[1].value=wtab[n]->cmd;
  614.     menu_load(1,9,MainMenu);
  615.     m_loadmenu(2,CommNames);
  616.     m_linkmenu(1,0,2,MF_SNIP);
  617.     m_selectmenu2(1);
  618. }
  619.  
  620. static UpdateMenu(n) int n; {
  621.     register int i;
  622.  
  623.     for (i=0; i<MAXWIN; i++)
  624.     if (wtab[i] && i!=n) {
  625.         m_selectwin(i);
  626.         m_loadmenu(2,CommNames);
  627.     }
  628. }
  629.  
  630. static Parse (buf, args) char *buf, **args; {
  631.     register char *p = buf, **ap = args;
  632.     register delim, argc = 0;
  633.  
  634.     argc = 0;
  635.     for (;;) {
  636.     while (*p && (*p == ' ' || *p == '\t')) ++p;
  637.     if (*p == '\0' || *p == '#')
  638.         return argc;
  639.     if (argc > MAXARGS-1)
  640.         Msg (0, "Too many tokens.");
  641.     delim = 0;
  642.     if (*p == '"' || *p == '\'') {
  643.         delim = *p; *p = '\0'; ++p;
  644.     }
  645.     ++argc;
  646.     *ap = p; ++ap;
  647.     while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t')))
  648.         ++p;
  649.     if (*p == '\0') {
  650.         if (delim)
  651.         Msg (0, "Missing quote.");
  652.         else
  653.         return argc;
  654.     }
  655.     *p++ = '\0';
  656.     }
  657. }
  658.  
  659. static char TermBuf[MAXLINE];
  660.  
  661. static MakeWindow (prog, args, name, dir)
  662.     char *prog, *name, **args, *dir; {
  663.     register struct win *p;
  664.     register char **cp;
  665.     register n, f;
  666.     int tf;
  667.     int mypid;
  668.     char ebuf[16];
  669.     char ibuf[MY_MAXLINE];
  670.     char *av[MAXARGS];
  671.     char *ptr,*index();
  672.  
  673.     if ((f = OpenPTY ()) == -1) {
  674.     Msg (0, "No more PTYs.");
  675.     return -1;
  676.     }
  677.     (void) fcntl (f, F_SETFL, FNDELAY);
  678.     if ((p = (struct win *)malloc (sizeof (struct win))) == 0) {
  679.     Msg (0, "Out of memory.");
  680.     return -1;
  681.     }
  682.     p->outful=0;
  683.     p->outptr=p->outbuf;
  684.  
  685.     m_ttyset();
  686.     if (!wtab[0]) {
  687.     n=0;
  688.     } else {
  689.     m_resetflags(CBREAK);
  690.     m_newwin(0,0,50,50);
  691.     read(0, TermBuf, MAXLINE);
  692.     TermBuf[MAXLINE-1]='\0';
  693.         n = atoi(&TermBuf[2]);
  694.     }
  695.         m_selectwin(n);
  696.         m_dupkey(Esc);
  697.     m_font(MyFont);
  698.         m_sizeall(n*5,n*5,80,24);
  699.     strcpy(TermBuf,"TERMCAP=");
  700.     m_getinfo(G_TERMCAP);
  701.     read(0, &TermBuf[6], MAXLINE);
  702.     TermBuf[MAXLINE-1]='\0';
  703.     m_setflags(CBREAK);
  704.     TermBuf[6]='P';
  705.     TermBuf[7]='=';
  706.     ptr=index(TermBuf,'\n');
  707.     *ptr='\0';
  708.     m_clear();
  709.     sprintf(ebuf,EventStr,Esc,n+'!');
  710.     m_setevent(ACTIVATE,ebuf);
  711.     ebuf[2]='D';
  712.     m_setevent(DESTROY,ebuf);
  713.     ebuf[2]='R';
  714.     m_setevent(RESHAPE,ebuf);
  715.     m_ttyreset();
  716.     wtab[n]=p;
  717.  
  718.     p->ptyfd = f;
  719.  
  720.     if (!prog) {
  721.     int argc;
  722.  
  723.     SetTTY(0, &OldMode);
  724.     printf("Enter command and arguments: ");
  725.     fflush(stdout);
  726.     ptr=gets(ibuf);
  727.     SetTTY(0, &NewMode);
  728.     if (!ptr || ((argc = Parse(ibuf, av)) == 0)) {
  729.         KillWindow(n);
  730.         return;
  731.     }
  732.     av[argc] = NULL;
  733.     if (strcmp(av[0],"-n") == 0) {
  734.         name=av[1];
  735.         args=(&av[2]);
  736.     } else 
  737.         args=av;
  738.     prog=args[0];
  739.     }
  740.  
  741.     strncpy (p->cmd, *name ? name : Filename (args[0]), MAXSTR-1);
  742.     p->cmd[MAXSTR-1] = '\0';
  743.  
  744.     CollectNames();
  745.     MakeMenu(n);
  746.     UpdateMenu(n);
  747.     strncpy (p->tty, TtyName, MAXSTR-1);
  748.     (void) chown (TtyName, getuid (), getgid ());
  749.     (void) chmod (TtyName, TtyMode);
  750.     p->slot = SetUtmp (TtyName);
  751.     p->rows=24;
  752.     p->cols=80;
  753.     switch (p->wpid = fork ()) {
  754.     case -1:
  755.     Msg (errno, "fork");
  756.     free ((char *)p);
  757.     return -1;
  758.     case 0:
  759.     signal (SIGHUP, SIG_DFL);
  760.     signal (SIGINT, SIG_DFL);
  761.     signal (SIGQUIT, SIG_DFL);
  762.     signal (SIGTERM, SIG_DFL);
  763.     signal (SIGTTIN, SIG_DFL);
  764.     signal (SIGTTOU, SIG_DFL);
  765.     setuid (getuid ());
  766.     setgid (getgid ());
  767.     if (dir && chdir (dir) == -1) {
  768.         SendErrorMsg ("Cannot chdir to %s: %s", dir, sys_errlist[errno]);
  769.         exit (1);
  770.     }
  771.     mypid = getpid ();
  772.     ioctl (DevTty, TIOCNOTTY, (char *)0);
  773.     if ((tf = open (TtyName, O_RDWR)) == -1) {
  774.         SendErrorMsg ("Cannot open %s: %s", TtyName, sys_errlist[errno]);
  775.         exit (1);
  776.     }
  777.     (void) dup2 (tf, 0);
  778.     (void) dup2 (tf, 1);
  779.     (void) dup2 (tf, 2);
  780.     for (f = getdtablesize () - 1; f > 2; f--)
  781.         close (f);
  782.     ioctl (0, TIOCSPGRP, &mypid);
  783.     (void) setpgrp (0, mypid);
  784.     SetTTY (0, &OldMode);
  785. #ifdef    TIOCSWINSZ
  786.     {
  787.         struct winsize wbuf;
  788.         wbuf.ws_row = p->rows;
  789.         wbuf.ws_col=p->cols;
  790.         ioctl (0, TIOCSWINSZ, &wbuf);
  791.     }
  792. #endif
  793.     NewEnv[2] = TermBuf;
  794.     sprintf (ebuf, "WINDOW=%d", n);
  795.     NewEnv[3] = ebuf;
  796.     execvpe (prog, args, NewEnv);
  797.     SendErrorMsg ("Cannot exec %s: %s", prog, sys_errlist[errno]);
  798.     exit (1);
  799.     }
  800.     return n;
  801. }
  802.  
  803. static execvpe (prog, args, env) char *prog, **args, **env; {
  804.     register char *path, *p;
  805.     char buf[1024];
  806.     char *shargs[MAXARGS+1];
  807.     register i, eaccess = 0;
  808.  
  809.     if (prog[0] == '/')
  810.     path = "";
  811.     else if ((path = getenv ("PATH")) == 0)
  812.     path = DefaultPath;
  813.     do {
  814.     p = buf;
  815.     while (*path && *path != ':')
  816.         *p++ = *path++;
  817.     if (p > buf)
  818.         *p++ = '/';
  819.     strcpy (p, prog);
  820.     if (*path)
  821.         ++path;
  822.     execve (buf, args, env);
  823.     switch (errno) {
  824.     case ENOEXEC:
  825.         shargs[0] = DefaultShell;
  826.         shargs[1] = buf;
  827.         for (i = 1; shargs[i+1] = args[i]; ++i)
  828.         ;
  829.         execve (DefaultShell, shargs, env);
  830.         return;
  831.     case EACCES:
  832.         eaccess = 1;
  833.         break;
  834.     case ENOMEM: case E2BIG: case ETXTBSY:
  835.         return;
  836.     }
  837.     } while (*path);
  838.     if (eaccess)
  839.     errno = EACCES;
  840. }
  841.  
  842. static OpenPTY () {
  843.     register char *p, *l, *d;
  844.     register i, f, tf;
  845.  
  846.     strcpy (PtyName, PtyProto);
  847.     strcpy (TtyName, TtyProto);
  848.     for (p = PtyName, i = 0; *p != 'X'; ++p, ++i) ;
  849.     for (l = "qpr"; *p = *l; ++l) {
  850.     for (d = "0123456789abcdef"; p[1] = *d; ++d) {
  851.         if ((f = open (PtyName, O_RDWR)) != -1) {
  852.         TtyName[i] = p[0];
  853.         TtyName[i+1] = p[1];
  854.         if ((tf = open (TtyName, O_RDWR)) != -1) {
  855.             close (tf);
  856.             return f;
  857.         }
  858.         close (f);
  859.         }
  860.     }
  861.     }
  862.     return -1;
  863. }
  864.  
  865. static SetTTY (fd, mp) struct mode *mp; {
  866.     ioctl (fd, TIOCSETP, &mp->m_ttyb);
  867.     ioctl (fd, TIOCSETC, &mp->m_tchars);
  868.     ioctl (fd, TIOCSLTC, &mp->m_ltchars);
  869.     ioctl (fd, TIOCLSET, &mp->m_lmode);
  870.     ioctl (fd, TIOCSETD, &mp->m_ldisc);
  871. }
  872.  
  873. static GetTTY (fd, mp) struct mode *mp; {
  874.     ioctl (fd, TIOCGETP, &mp->m_ttyb);
  875.     ioctl (fd, TIOCGETC, &mp->m_tchars);
  876.     ioctl (fd, TIOCGLTC, &mp->m_ltchars);
  877.     ioctl (fd, TIOCLGET, &mp->m_lmode);
  878.     ioctl (fd, TIOCGETD, &mp->m_ldisc);
  879. }
  880.  
  881. static SetMode (op, np) struct mode *op, *np; {
  882.     *np = *op;
  883.     np->m_ttyb.sg_flags &= ~(CRMOD|ECHO);
  884.     np->m_ttyb.sg_flags |= CBREAK;
  885.     np->m_tchars.t_intrc = -1;
  886.     np->m_tchars.t_quitc = -1;
  887.     np->m_ltchars.t_suspc = -1;
  888.     np->m_ltchars.t_dsuspc = -1;
  889.     np->m_ltchars.t_flushc = -1;
  890.     np->m_ltchars.t_lnextc = -1;
  891. }
  892.  
  893. static char *GetTtyName () {
  894.     register char *p;
  895.     register n;
  896.  
  897.     for (p = 0, n = 0; n <= 2 && !(p = ttyname (n)); n++)
  898.     ;
  899.     if (!p || *p == '\0')
  900.     Msg (0, "rmgr must run on a tty.");
  901.     return p;
  902. }
  903.  
  904. static Attach (how) {
  905.     register s, lasts, found = 0;
  906.     register DIR *dirp;
  907.     register struct direct *dp;
  908.     struct msg m;
  909.     char last[MAXNAMLEN+1];
  910.  
  911.     if (SockName) {
  912.     if ((lasts = MakeClientSocket (0)) == -1)
  913.         if (how == MSG_CONT)
  914.         Msg (0,
  915.             "This session has already been continued from elsewhere.");
  916.         else
  917.         Msg (0, "There is no session to be resumed from %s.", SockName);
  918.     } else {
  919.     if ((dirp = opendir (SockPath)) == NULL)
  920.         Msg (0, "Cannot open %s", SockPath);
  921.     while ((dp = readdir (dirp)) != NULL) {
  922.         SockName = dp->d_name;
  923.         if (SockName[0] == '.')
  924.         continue;
  925.         if ((s = MakeClientSocket (0)) != -1) {
  926.         if (found == 0) {
  927.             strcpy (last, SockName);
  928.             lasts = s;
  929.         } else {
  930.             if (found == 1) {
  931.             printf ("There are detached sessions on:\n");
  932.             printf ("   %s\n", last);
  933.             close (lasts);
  934.             }
  935.             printf ("   %s\n", SockName);
  936.             close (s);
  937.         }
  938.         found++;
  939.         }
  940.     }
  941.     if (found == 0)
  942.         Msg (0, "There is no session to be resumed.");
  943.     if (found > 1)
  944.         Msg (0, "Type \"rmgr -r host.tty\" to resume one of them.");
  945.     closedir (dirp);
  946.     strcpy (SockNamePtr, last);
  947.     SockName = SockNamePtr;
  948.     }
  949.     m.type = how;
  950.     strcpy (m.m.attach.tty, GetTtyName ());
  951.     m.m.attach.apid = getpid ();
  952.     if (write (lasts, (char *)&m, sizeof (m)) != sizeof (m))
  953.     Msg (errno, "write");
  954. }
  955.  
  956. static void AttacherFinit () {
  957.     exit (0);
  958. }
  959.  
  960. static void ReAttach () {
  961.     Attach (MSG_CONT);
  962. }
  963.  
  964. static Attacher () {
  965.     signal (SIGHUP, AttacherFinit);
  966.     signal (SIGCONT, ReAttach);
  967.     while (1)
  968.     pause ();
  969. }
  970.  
  971. static Detach (suspend) {
  972.     register struct win **pp;
  973.     register int i;
  974.  
  975.     if (Detached)
  976.     return;
  977.     signal (SIGHUP, SIG_IGN);
  978.     if (VoluntaryDetach) {    /* Can't save state if line dropped */
  979.     for (i=MAXWIN-1;i>0;i--) {
  980.     if (wtab[i]) {
  981.     m_selectwin(i);
  982.     m_nomenu2();
  983.     m_push(P_EVENT);
  984.         }
  985.     }
  986.     m_selectwin(0);
  987.     m_nomenu2(); m_nomenu();
  988.     m_push(P_ALL);
  989.     m_setmode(M_ACTIVATE);
  990.     }
  991.     SetTTY (0, &OldMode);
  992.     if (suspend) {
  993.     Kill (AttacherPid, SIGTSTP);
  994.     for (pp=wtab; pp < wtab+MAXWIN; ++pp)
  995.         if (*pp) (*pp)->win_ok=1;
  996.     } else {
  997.     for (pp=wtab; pp < wtab+MAXWIN; ++pp)
  998.         if (*pp) RemoveUtmp ((*pp)->slot);
  999.     printf ("\n[detached]\n");
  1000.     Kill (AttacherPid, SIGHUP);
  1001.     AttacherPid = 0;
  1002.     }
  1003.     close (0);
  1004.     close (1);
  1005.     close (2);
  1006.     ioctl (DevTty, TIOCNOTTY, (char *)0);
  1007.     Detached = 1;
  1008.     do {
  1009.     ReceiveMsg (ServerSocket); 
  1010.     } while (Detached);
  1011.     if (!suspend) {
  1012.     for (pp = wtab; pp < wtab+MAXWIN; ++pp)
  1013.         if (*pp) (*pp)->slot = SetUtmp ((*pp)->tty);
  1014.     }
  1015.     signal (SIGHUP, SigHup);
  1016. }
  1017.  
  1018. static Kill (pid, sig) {
  1019.     if (pid != 0)
  1020.     (void) kill (pid, sig);
  1021. }
  1022.  
  1023. static GetSockName () {
  1024.     register client;
  1025.     static char buf[2*MAXSTR];
  1026.  
  1027.     if ((SockName = getenv ("STY")) != 0 && *SockName != '\0') {
  1028.     client = 1;
  1029.     setuid (getuid ());
  1030.     setgid (getgid ());
  1031.     } else {
  1032.     sprintf (buf, "%s.%s", HostName, Filename (GetTtyName ()));
  1033.     SockName = buf;
  1034.     client = 0;
  1035.     }
  1036.     return client;
  1037. }
  1038.  
  1039. static MakeServerSocket () {
  1040.     register s;
  1041.     struct sockaddr_un a;
  1042.     char *p;
  1043.  
  1044.     if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
  1045.     Msg (errno, "socket");
  1046.     a.sun_family = AF_UNIX;
  1047.     strcpy (SockNamePtr, SockName);
  1048.     strcpy (a.sun_path, SockPath);
  1049.     if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) != -1) {
  1050.     p = Filename (SockPath);
  1051.     Msg (0, "You already have a session running on %s.\n\
  1052. If it has been detached, try \"rmgr -r\".", p);
  1053.     /*NOTREACHED*/
  1054.     }
  1055.     (void) unlink (SockPath);
  1056.     if (bind (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1)
  1057.     Msg (errno, "bind");
  1058.     (void) chown (SockPath, getuid (), getgid ());
  1059.     if (listen (s, 5) == -1)
  1060.     Msg (errno, "listen");
  1061.     return s;
  1062. }
  1063.  
  1064. static MakeClientSocket (err) {
  1065.     register s;
  1066.     struct sockaddr_un a;
  1067.  
  1068.     if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
  1069.     Msg (errno, "socket");
  1070.     a.sun_family = AF_UNIX;
  1071.     strcpy (SockNamePtr, SockName);
  1072.     strcpy (a.sun_path, SockPath);
  1073.     if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1) {
  1074.     if (err) {
  1075.         Msg (errno, "connect: %s", SockPath);
  1076.     } else {
  1077.         close (s);
  1078.         return -1;
  1079.     }
  1080.     }
  1081.     return s;
  1082. }
  1083.  
  1084. static SendCreateMsg (s, ac, av, name) char **av, *name; {
  1085.     struct msg m;
  1086.     register char *p;
  1087.     register len, n;
  1088.  
  1089.     m.type = MSG_CREATE;
  1090.     p = m.m.create.line;
  1091.     for (n = 0; ac > 0 && n < MAXARGS-1; ++av, --ac, ++n) {
  1092.     len = strlen (*av) + 1;
  1093.     if (p + len >= m.m.create.line+MY_MAXLINE)
  1094.         break;
  1095.     strcpy (p, *av);
  1096.     p += len;
  1097.     }
  1098.     m.m.create.nargs = n;
  1099.     if (name)
  1100.     strcpy(m.m.create.name,name);
  1101.     else
  1102.     m.m.create.name[0]='\0';
  1103.     if (getwd (m.m.create.dir) == 0)
  1104.     Msg (0, "%s", m.m.create.dir);
  1105.     if (write (s, (char *)&m, sizeof (m)) != sizeof (m))
  1106.     Msg (errno, "write");
  1107. }
  1108.  
  1109. /*VARARGS1*/
  1110. static SendErrorMsg (fmt, p1, p2, p3, p4, p5, p6) char *fmt; {
  1111.     register s;
  1112.     struct msg m;
  1113.  
  1114.     s = MakeClientSocket (1);
  1115.     m.type = MSG_ERROR;
  1116.     sprintf (m.m.message, fmt, p1, p2, p3, p4, p5, p6);
  1117.     (void) write (s, (char *)&m, sizeof (m));
  1118.     close (s);
  1119.     sleep (2);
  1120. }
  1121.  
  1122. static char m_rbuf[MAXLINE];
  1123.  
  1124. static char *m_read() {
  1125.     register char *ptr; char *index();
  1126.     register int i;
  1127.  
  1128.     i=read(0,m_rbuf,MAXLINE-1);
  1129.     m_rbuf[i]='\0';
  1130.     ptr=index(m_rbuf,Esc);
  1131.     if (!ptr)
  1132.     ptr=m_rbuf;
  1133.     else
  1134.     ptr++;
  1135.     return(ptr);
  1136. }
  1137.  
  1138. static ReplayWindow(p) struct win *p; {
  1139.     register int n;
  1140.  
  1141.     n=p->outptr-p->outbuf;
  1142.     if (p->outful)        /* Replay last screen of data */
  1143.         write(1,p->outptr,SCRBUFSIZE-n);
  1144.     write(1,p->outbuf,n);
  1145. }
  1146.  
  1147. static RestoreWindows(mt) int mt; {
  1148.     register int i, j=0;
  1149.     struct window_data wd;
  1150.     register char *ptr;
  1151.     register struct win *p;
  1152.     char buf[8];
  1153.     int n, nw;
  1154.     int oldset=1;
  1155.  
  1156.     if (mt != MSG_CONT) {    /* Restore after a detach, not suspend */
  1157.     linemode(1);
  1158.     for (i=MAXWIN-1; i>=0; i--) {
  1159.     m_selectwin(i);
  1160.     m_getinfo(G_ID);
  1161.     ptr=m_read();
  1162.     sscanf(ptr,"%d %d",&n, &nw);
  1163.     if (wtab[i]) {
  1164.         p=wtab[i];
  1165.         if (n!=i) {        /* That one didn't exist, remake it... */
  1166.         oldset=0;    /* Looks like the old context is gone. */
  1167.         m_newwin(j,j,50,50);
  1168.         ptr=m_read();
  1169.         n=atoi(ptr);
  1170.         if (!n) 
  1171.             Msg(0, "Error restoring window.");
  1172.         m_selectwin(n);
  1173.         }
  1174.         if (!oldset) {
  1175.         m_size(p->cols,p->rows);
  1176.             m_dupkey(Esc);
  1177.             sprintf(buf,EventStr,Esc,n+'!');
  1178.             m_setevent(ACTIVATE,buf);
  1179.             buf[2]='D';
  1180.             m_setevent(DESTROY,buf);
  1181.             buf[2]='R';
  1182.             m_setevent(RESHAPE,buf);
  1183.         MakeMenu(n);
  1184.         ReplayWindow(p);
  1185.         } else if (VoluntaryDetach) {
  1186.         m_pop();
  1187.         } else ReplayWindow(p);    /* Redraw for hangup */
  1188.     } else if (i) {        /* Gee, a window we didn't create. Byebye. */
  1189.         oldset=0;        /* Again, we must have lost the old stuff */
  1190.         m_destroywin(i);
  1191.     }
  1192.     }
  1193.     linemode(0);
  1194.     } else {
  1195.     for (i=0;i<MAXWIN;i++) {
  1196.         p=wtab[i];
  1197.         if (p) {
  1198.         m_selectwin(i);
  1199.         m_pop();
  1200.         m_selectmenu2(1);
  1201.         if (!p->win_ok)
  1202.             ReplayWindow(p);
  1203.         }
  1204.     }
  1205.     }
  1206.     VoluntaryDetach=0;
  1207. }
  1208.         
  1209. static ReceiveMsg (s) {
  1210.     register ns;
  1211.     struct sockaddr_un a;
  1212.     int left, len = sizeof (a);
  1213.     struct msg m;
  1214.     char *p;
  1215.  
  1216.     if ((ns = accept (s, (struct sockaddr *)&a, &len)) == -1) {
  1217.     Msg (errno, "accept");
  1218.     return;
  1219.     }
  1220.     p = (char *)&m;
  1221.     left = sizeof (m);
  1222.     while (left > 0 && (len = read (ns, p, left)) > 0) {
  1223.     p += len;
  1224.     left -= len;
  1225.     }
  1226.     close (ns);
  1227.     if (len == -1)
  1228.     Msg (errno, "read");
  1229.     if (left > 0)
  1230.     return;
  1231.     switch (m.type) {
  1232.     case MSG_CREATE:
  1233.     if (!Detached)
  1234.         ExecCreate (&m);
  1235.     break;
  1236.     case MSG_CONT:
  1237.     if (m.m.attach.apid != AttacherPid || !Detached)
  1238.         break;    /* Intruder Alert */
  1239.     /*FALLTHROUGH*/
  1240.     case MSG_ATTACH:
  1241.     if (Detached) {
  1242.         if (kill (m.m.attach.apid, 0) == 0 &&
  1243.             open (m.m.attach.tty, O_RDWR) == 0) {
  1244.         (void) dup (0);
  1245.         (void) dup (0);
  1246.         AttacherPid = m.m.attach.apid;
  1247.         Detached = 0;
  1248.         GetTTY (0, &OldMode);
  1249.         SetMode (&OldMode, &NewMode);
  1250.         SetTTY (0, &NewMode);
  1251.         RestoreWindows(m.type);
  1252.         SwitchWindow(CurrNum);
  1253.         }
  1254.     } else {
  1255.         Kill (m.m.attach.apid, SIGHUP);
  1256.         Msg (0, "Not detached.");
  1257.     }
  1258.     break;
  1259.     case MSG_ERROR:
  1260.     Msg (0, "%s", m.m.message);
  1261.     break;
  1262.     default:
  1263.     Msg (0, "Invalid message (type %d).", m.type);
  1264.     }
  1265. }
  1266.  
  1267. static ExecCreate (mp) struct msg *mp; {
  1268.     char *args[MAXARGS];
  1269.     register n;
  1270.     register char **pp = args, *p = mp->m.create.line;
  1271.  
  1272.     for (n = mp->m.create.nargs; n > 0; --n) {
  1273.     *pp++ = p;
  1274.     p += strlen (p) + 1;
  1275.     }
  1276.     *pp = 0;
  1277.     if ((n = MakeWindow (mp->m.create.line, args, mp->m.create.name,
  1278.         mp->m.create.dir)) != -1)
  1279.     SwitchWindow (n);
  1280. }
  1281.  
  1282. static char **SaveArgs (argc, argv) register argc; register char **argv; {
  1283.     register char **ap, **pp;
  1284.  
  1285.     if ((pp = ap = (char **)malloc ((argc+1) * sizeof (char **))) == 0)
  1286.     Msg (0, "Out of memory.");
  1287.     while (argc--) {
  1288.     if ((*pp = malloc (strlen (*argv)+1)) == 0)
  1289.         Msg (0, "Out of memory.");
  1290.     strcpy (*pp, *argv);
  1291.     ++pp; ++argv;
  1292.     }
  1293.     *pp = 0;
  1294.     return ap;
  1295. }
  1296.  
  1297. static MakeNewEnv () {
  1298.     register char **op, **np = NewEnv;
  1299.     static char buf[MAXSTR];
  1300.  
  1301.     if (strlen (SockName) > MAXSTR-5)
  1302.     SockName = "?";
  1303.     sprintf (buf, "STY=%s", SockName);
  1304.     *np++ = buf;
  1305.     *np++ = "TERM=mgr";
  1306.     np += 2;
  1307.     for (op = environ; *op; ++op) {
  1308.     if (np == NewEnv + MAXARGS - 1)
  1309.         break;
  1310.     if (!IsSymbol (*op, "TERM") && !IsSymbol (*op, "TERMCAP")
  1311.         && !IsSymbol (*op, "STY"))
  1312.         *np++ = *op;
  1313.     }
  1314.     *np = 0;
  1315. }
  1316.  
  1317. static IsSymbol (e, s) register char *e, *s; {
  1318.     register char *p;
  1319.     register n;
  1320.  
  1321.     for (p = e; *p && *p != '='; ++p) ;
  1322.     if (*p) {
  1323.     *p = '\0';
  1324.     n = strcmp (e, s);
  1325.     *p = '=';
  1326.     return n == 0;
  1327.     }
  1328.     return 0;
  1329. }
  1330.  
  1331. /*VARARGS2*/
  1332. Msg (err, fmt, p1, p2, p3, p4, p5, p6) char *fmt; {
  1333.     char buf[1024];
  1334.     register char *p = buf;
  1335.  
  1336.     if (Detached)
  1337.     return;
  1338.     sprintf (p, fmt, p1, p2, p3, p4, p5, p6);
  1339.     if (err) {
  1340.     p += strlen (p);
  1341.     if (err > 0 && err < sys_nerr)
  1342.         sprintf (p, ": %s", sys_errlist[err]);
  1343.     else
  1344.         sprintf (p, ": Error %d", err);
  1345.     }
  1346.     printf ("%s\r\n", buf);
  1347.     if (!HasWindow) {
  1348.     Kill (AttacherPid, SIGHUP);
  1349.     exit (1);
  1350.     }
  1351. }
  1352.  
  1353. static char *Filename (s) char *s; {
  1354.     register char *p;
  1355.  
  1356.     p = s + strlen (s) - 1;
  1357.     while (p >= s && *p != '/') --p;
  1358.     return ++p;
  1359. }
  1360.  
  1361. static IsNum (s, base) register char *s; register base; {
  1362.     for (base += '0'; *s; ++s)
  1363.     if (*s < '0' || *s > base)
  1364.         return 0;
  1365.     return 1;
  1366. }
  1367.  
  1368. static InitUtmp () {
  1369.     struct passwd *p;
  1370.  
  1371.     if ((utmpf = open (UtmpName, O_WRONLY)) == -1) {
  1372.     if (errno != EACCES)
  1373.         Msg (errno, UtmpName);
  1374.     return;
  1375.     }
  1376.     if ((LoginName = getlogin ()) == 0 || LoginName[0] == '\0') {
  1377.     if ((p = getpwuid (getuid ())) == 0)
  1378.         return;
  1379.     LoginName = p->pw_name;
  1380.     }
  1381.     utmp = 1;
  1382. }
  1383.  
  1384. static SetUtmp (name) char *name; {
  1385.     register char *p;
  1386.     register struct ttyent *tp;
  1387.     register slot = 1;
  1388.     struct utmp u;
  1389.  
  1390.     if (!utmp)
  1391.     return 0;
  1392.     if (p = rindex (name, '/'))
  1393.     ++p;
  1394.     else p = name;
  1395.     setttyent ();
  1396.     while ((tp = getttyent ()) != NULL && strcmp (p, tp->ty_name) != 0)
  1397.     ++slot;
  1398.     if (tp == NULL)
  1399.     return 0;
  1400.     strncpy (u.ut_line, p, 8);
  1401.     strncpy (u.ut_name, LoginName, 8);
  1402.     u.ut_host[0] = '\0';
  1403.     time (&u.ut_time);
  1404.     (void) lseek (utmpf, (long)(slot * sizeof (u)), 0);
  1405.     (void) write (utmpf, (char *)&u, sizeof (u));
  1406.     return slot;
  1407. }
  1408.  
  1409. static RemoveUtmp (slot) {
  1410.     struct utmp u;
  1411.  
  1412.     if (slot) {
  1413.     bzero ((char *)&u, sizeof (u));
  1414.     (void) lseek (utmpf, (long)(slot * sizeof (u)), 0);
  1415.     (void) write (utmpf, (char *)&u, sizeof (u));
  1416.     }
  1417. }
  1418.  
  1419. #ifndef GETTTYENT
  1420.  
  1421. static setttyent () {
  1422.     struct stat s;
  1423.     register f;
  1424.     register char *p, *ep;
  1425.  
  1426.     if (ttnext) {
  1427.     ttnext = tt;
  1428.     return;
  1429.     }
  1430.     if ((f = open (ttys, O_RDONLY)) == -1 || fstat (f, &s) == -1)
  1431.     Msg (errno, ttys);
  1432.     if ((tt = malloc (s.st_size + 1)) == 0)
  1433.     Msg (0, "Out of memory.");
  1434.     if (read (f, tt, s.st_size) != s.st_size)
  1435.     Msg (errno, ttys);
  1436.     close (f);
  1437.     for (p = tt, ep = p + s.st_size; p < ep; ++p)
  1438.     if (*p == '\n') *p = '\0';
  1439.     *p = '\0';
  1440.     ttnext = tt;
  1441. }
  1442.  
  1443. static struct ttyent *getttyent () {
  1444.     static struct ttyent t;
  1445.  
  1446.     if (*ttnext == '\0')
  1447.     return NULL;
  1448.     t.ty_name = ttnext + 2;
  1449.     ttnext += strlen (ttnext) + 1;
  1450.     return &t;
  1451. }
  1452.  
  1453. #endif
  1454.  
  1455. #ifndef USEBCOPY
  1456. bcopy (s1, s2, len) register char *s1, *s2; register len; {
  1457.     if (s1 < s2 && s2 < s1 + len) {
  1458.     s1 += len; s2 += len;
  1459.     while (len-- > 0) {
  1460.         *--s2 = *--s1;
  1461.     }
  1462.     } else {
  1463.     while (len-- > 0) {
  1464.         *s2++ = *s1++;
  1465.     }
  1466.     }
  1467. }
  1468. #endif
  1469.